home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 1 / PC Actual CD 01.iso / f1 / cimb.arj / COLOR.C < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-07  |  14.2 KB  |  574 lines

  1. /*==============================================================================
  2.  
  3. FICHERO: COLOR.C
  4.  
  5. AUTOR: ANTONIO LADESA JURADO
  6.  
  7. FECHA: 24/6/94
  8.  
  9. DESCRIPCION:
  10.  
  11.     Fichero que contiene las estructuras, constantes, variables y funciones
  12.     internas y externas para el tratamiento del color de las imágenes.
  13.  
  14. ==============================================================================*/
  15.  
  16.  
  17. /*---- MODULOS USADOS --------------------------------------------------------*/
  18.  
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <alloc.h>
  23. #include <string.h>
  24.  
  25. #include "global.h"
  26. #include "memoria.h"
  27. #include "video.h"
  28. #include "color.h"
  29. #include "error.h"
  30. #include "mapagris.pal"
  31.  
  32. /*---- ESTRUCTURAS, CONSTANTES Y VARIABLES LOCALES AL MODULO -----------------*/
  33.  
  34.     /* pattern usado en el algoritmo de Bayer */
  35. static char BAYERpatron[8][8] =
  36. {
  37.  0,32, 8,40, 2,34,10,42,
  38. 48,16,56,24,50,18,58,26,
  39. 12,44, 4,36,14,46, 6,38,
  40. 60,28,52,20,62,30,54,22,
  41.  3,35,11,43, 1,33, 9,41,
  42. 51,19,59,27,49,17,57,25,
  43. 15,47, 7,39,13,45, 5,37,
  44. 63,31,55,23,61,29,53,21
  45. };
  46.  
  47.     /* buffers de entrada y salida para dither */
  48. char BufferEntrada[3][ANCHO_MAXIMO];
  49. char BufferSalida[ANCHO_MAXIMO];
  50.     /* metodo dither usado */
  51. char metodo;
  52.     /* niveles de gris equivalentes a blanco y negro */
  53. int blanco,negro;
  54.     /* ultima línea procesada por el algoritmo de dither */
  55. int ultima;
  56.     /* anchura y altura de la imagen, globales para el dither */
  57. int anchura,altura;
  58.  
  59. /*---- DEFINICION DE LAS FUNCIONES INTERNAS ----------------------------------*/
  60.  
  61. void DITHERpixel(int x,int y,int err);
  62. void ObtenerByN(int n,char *paleta);
  63. int LeerPixel(int x,int y);
  64. void PonerPixel(int x,int y,int n);
  65. void EscribirPixel(int x,int y,int n);
  66.  
  67. /*---- CODIFICACION DE LAS FUNCIONES OFRECIDAS -------------------------------*/
  68.  
  69.  
  70. /*---- FUNCION: extern IMAGEN *PonerGris(IMAGEN *c) ----------------------------
  71.  
  72.     Descripción:
  73.  
  74.         Esta función transforma una imagen a color en tonos de gris.
  75.  
  76.     Parámetros:
  77.  
  78.         IMAGEN *c : puntero a estructura que alberga la imagen
  79.  
  80.     Retorno:
  81.  
  82.         Puntero a la estructura de la imagen convertida.
  83.         Si hay error, devuelve la misma imagen.
  84.  
  85. ---- CODIGO: -----------------------------------------------------------------*/
  86.  
  87. extern IMAGEN *PonerGris(IMAGEN *c)
  88. {
  89.     /* puntero auxiliar a paleta */
  90. char *p;
  91.     /* contador */
  92. int i;
  93.     /* color obtenido */
  94. double color;
  95.  
  96. switch(c->modo)
  97.     {
  98.     case VIDEOega:
  99.     case VIDEOvga:
  100.             /* si tiene paleta, se calculan los grises */
  101.         if(c->haypaleta)
  102.             {
  103.             p = c->paleta;
  104.                 /* para todos los colores... */
  105.             for(i=0;i<c->colores;++i,p+=3)
  106.                 {
  107.                     /* calcular nivel de gris */
  108.                 color = (0.30*(double)*p)+
  109.                                 (0.59*(double)*(p+1))+
  110.                                 (0.11*(double)*(p+2));
  111.                 if(color > 255.0)
  112.                     color = 255.0;
  113.                     /* poner gris los 3 componentes (RGB) */
  114.                 memset(p,mapagris[(char)color],3);
  115.                 }
  116.             }
  117.         else
  118.             /* si no tiene paleta, crearla */
  119.             {
  120.             p = c->paleta;
  121.             for(i=0;i<c->colores;++i,p+=3)
  122.                 memset(p,mapagris[i],3);
  123.             c->haypaleta++;
  124.             }
  125.     break;
  126.     };
  127. return(c);
  128. }
  129.  
  130. /*---- FIN FUNCION -----------------------------------------------------------*/
  131.  
  132.  
  133. /*---- FUNCION: extern IMAGEN *VideoInverso(IMAGEN *c) -------------------------
  134.  
  135.     Descripción:
  136.  
  137.         Esta función transforma una imagen en su negativo.
  138.  
  139.     Parámetros:
  140.  
  141.         IMAGEN *c : puntero a estructura que alberga la imagen
  142.  
  143.     Retorno:
  144.  
  145.         Puntero a la estructura de la imagen convertida.
  146.         Si hay error, devuelve la misma imagen.
  147.  
  148. ---- CODIGO: -----------------------------------------------------------------*/
  149.  
  150. extern IMAGEN *VideoInverso(IMAGEN *c)
  151. {
  152.     /* contadores */
  153. int i,j;
  154.     /* buffer para la línea */
  155. char buffer[ANCHO_MAXIMO];
  156.  
  157.     /* si es monocromática, cambiar blanco por negro */
  158. if(c->modo==VIDEOmono)
  159.     for(i=0;i<c->alto;++i)
  160.         {
  161.         MEMleer(buffer,i,c);
  162.         for(j=0;j<c->ancho;++j)
  163.             *(buffer+j) = ~(*(buffer+j));
  164.         MEMescribir(buffer,i,c);
  165.         }
  166. else
  167.         /* si es de color, invertir los colores de la paleta */
  168.     {
  169.     j=c->colores*3;
  170.     for(i=0;i<j;i++)
  171.         c->paleta[i] = 255 - c->paleta[i];
  172.     }
  173. return(c);
  174. }
  175.  
  176. /*---- FIN FUNCION -----------------------------------------------------------*/
  177.  
  178.  
  179. /*---- FUNCION: extern IMAGEN *EscalarColores(IMAGEN *c,int colores) -----------
  180.  
  181.     Descripción:
  182.  
  183.         Esta función amplía o reduce el número de colores de una imagen.
  184.  
  185.     Parámetros:
  186.  
  187.         IMAGEN *c : puntero a estructura que alberga la imagen
  188.         int colores : nuevo número de colores de la imagen
  189.     Retorno:
  190.  
  191.         Puntero a la estructura de la imagen convertida.
  192.         Si hay error, devuelve la misma imagen.
  193.  
  194. ---- CODIGO: -----------------------------------------------------------------*/
  195.  
  196. extern IMAGEN *EscalarColores(IMAGEN *c,int colores)
  197. {
  198.     /* buffer de línea */
  199. char bufferVGA[ANCHO_MAXIMO];
  200.     /* contadores */
  201. int i,j;
  202.     /* factor de reducción/ampliación de colores */
  203. double factor;
  204.     /* nueva paleta de colores */
  205. char paleta[768];
  206.  
  207.     /* si no hay escalado, volver */
  208. if(c->colores == colores)
  209.     return(c);
  210.  
  211.     /* calcular factor de escalado de colores */
  212. factor=(double)colores/(double)c->colores;
  213. memset(paleta,0,768);
  214.     /* crear nueva paleta de colores */
  215. for(i=0;i<colores;++i)
  216.     {
  217.     paleta[i*3] = c->paleta[(i/factor)*3];
  218.     paleta[i*3+1] = c->paleta[(i/factor)*3+1];
  219.     paleta[i*3+2] = c->paleta[(i/factor)*3+2];
  220.     }
  221.     /* copiar nueva paleta */
  222. memcpy(c->paleta,paleta,768);
  223.     /* ajustar índices de la imagen a la paleta */
  224. for(i=0;i<c->alto;++i)
  225.     {
  226.     MEMleer(bufferVGA,i,c);
  227.     for(j=0;j<c->ancho;++j)
  228.         bufferVGA[j] = (double)bufferVGA[j]*factor;
  229.     MEMescribir(bufferVGA,i,c);
  230.     }
  231. c->colores = colores;
  232. return(c);
  233. }
  234.  
  235. /*---- FIN FUNCION -----------------------------------------------------------*/
  236.  
  237.  
  238. /*---- FUNCION: extern IMAGEN *BlancoYNegro(IMAGEN *c,char m) ------------------
  239.  
  240.     Descripción:
  241.  
  242.         Esta función transforma una imagen a color en blanco y negro.
  243.         Para ello usa un método de dithering:
  244.             Bayer, Floid-Steinberg, Stucki o Burkes.
  245.  
  246.     Parámetros:
  247.  
  248.         IMAGEN *c : puntero a estructura que alberga la imagen
  249.         char m: método usado
  250.  
  251.     Retorno:
  252.  
  253.         Puntero a la estructura de la imagen convertida.
  254.         Si hay error, devuelve la misma imagen.
  255.  
  256. ---- CODIGO: -----------------------------------------------------------------*/
  257.  
  258. extern IMAGEN *BlancoYNegro(IMAGEN *c,char m)
  259. {
  260.     /* puntero a la nueva imagen */
  261. IMAGEN *byn = NULL;
  262.     /* error de difusion */
  263. int err;
  264.     /* coordenadas del pixel a tratar */
  265. int x,y;
  266.     /* contadores de línea */
  267. int z,ln;
  268.     /* color en proceso */
  269. int n;
  270.  
  271.     /* si no hay imagen, error */
  272. if(c == NULL)
  273.     {
  274.     ERRORponer(ERRnoImagen);
  275.     return(c);
  276.     }
  277.  
  278.      /* reservar memoria para la cabecera de trabajo */
  279. if((byn=MEMreservarCAB(byn))==NULL)
  280.     {
  281.     ERRORponer(ERRnoMemoria);
  282.     return(c);
  283.     }
  284.  
  285.     /* obtener niveles de blanco y negro */
  286. ObtenerByN(c->colores,c->paleta);
  287.  
  288.     /* cargar cabecera de trabajo */
  289. strcpy(byn->nombre,c->nombre);
  290. byn->ancho = c->ancho & 0xFFF7;
  291. byn->alto = c->alto;
  292. byn->formato = c->formato;
  293. byn->modo = VIDEOmono;
  294. byn->colores = 2;
  295. byn->haypaleta = 0;
  296. byn->bytes = DePixelsABytes(c->ancho);
  297. if(byn->bytes & 1) byn->bytes++;
  298. anchura = c->ancho;
  299. altura = c->alto;
  300. metodo = m;
  301.  
  302.     /* reservar memoria para la imagen */
  303. if(!MEMreservar(byn))
  304.     {
  305.     byn =MEMliberar(byn);
  306.     return(c);
  307.     }
  308.  
  309.     /* determinar líneas de trabajo, según el método usado */
  310. switch(metodo)
  311.     {
  312.     case BAYER:ln=1;    break;
  313.     case FLOYD:ln=2;    break;
  314.     case STUCKI:ln=3;    break;
  315.     case BURKES:ln=3;    break;
  316.     }
  317.  
  318.     /* proceso */
  319. for(y=0;y<altura;++y)
  320.     {
  321.     ultima=y;
  322.  
  323.         /* leer las líneas requeridas por el método en uso */
  324.     for(z=0;z<ln;++z)
  325.         {
  326.         if((y+z)<c->alto)
  327.             MEMleer(BufferEntrada[z],y+z,c);
  328.         }
  329.  
  330.         /* limpiar buffer de salida */
  331.     memset(BufferSalida,0,ANCHO_MAXIMO);
  332.  
  333.         /* para cada pixel x de la línea y... */
  334.     for(x=0;x<anchura;++x)
  335.         {
  336.             /* si es dither Bayer, leer pixel y escribirlo según el patrón */
  337.         if(metodo == BAYER)
  338.             {
  339.             n = LeerPixel(x,y);
  340.                 /* si lo supera, escribir blanco */
  341.             if((n>>2) > BAYERpatron[x&7][y&7])
  342.                 EscribirPixel(x,y,1);
  343.             else
  344.                 /* si no, escribir negro */
  345.                 EscribirPixel(x,y,0);
  346.             continue;
  347.             }
  348.  
  349.             /* si es otro método, leer pixel */ 
  350.         if((n=LeerPixel(x,y))>((blanco+negro)/2))
  351.             {
  352.                 /* Si supera el umbral, escribir blanco */
  353.             EscribirPixel(x,y,1);
  354.                 /* establecer error de difusión, color menos nivel de blanco */
  355.             err=n-blanco;
  356.             }
  357.         else
  358.             {
  359.                 /* Si no supera el umbral, escribir negro */
  360.             EscribirPixel(x,y,0);
  361.                 /* establecer error de difusión, color menos nivel de negro */
  362.             err=n-negro;
  363.             }
  364.             /* aplicar el método de dithering */
  365.         DITHERpixel(x,y,err);
  366.         }
  367.  
  368.         /* si no es Bayer, escribir las líneas con los errores difundidos */
  369.     for(z=1;z<ln;++z)
  370.         {
  371.         if((y+z)<c->alto)
  372.             MEMescribir(BufferEntrada[z],y+z,c);
  373.         }
  374.  
  375.         /* escribir la línea resultante */
  376.     MEMescribir(BufferSalida,y,byn);
  377.     }
  378.  
  379.     /* liberar imagen anterior y devolver la nueva */
  380. c = MEMliberar(c);
  381. c = NULL;
  382. return(byn);
  383. }
  384.  
  385. /*---- FIN FUNCION -----------------------------------------------------------*/
  386.  
  387. /*---- CODIFICACION DE LAS FUNCIONES INTERNAS --------------------------------*/
  388.  
  389.  
  390. /*---- FUNCION: void ObtenerByN(int n,char *paleta) ----------------------------
  391.  
  392.     Descripción:
  393.  
  394.         Esta función determina los niveles para blanco y negro de una imagen
  395.         según su paleta y número de colores
  396.  
  397.     Parámetros:
  398.  
  399.         int n: número de colores
  400.         char *paleta: paleta de colores
  401.  
  402.     Retorno:
  403.  
  404.         Actualiza las variables globales blanco y negro
  405.  
  406. ---- CODIGO: -----------------------------------------------------------------*/
  407.  
  408. void ObtenerByN(int n,char *paleta)
  409. {
  410.     /* paleta auxiliar */
  411. char paletagris[256];
  412.     /* gris obtenido */
  413. double f;
  414.     /* contador */
  415. int i;
  416.  
  417.     /* niveles de blanco y negro */
  418. blanco = 0;
  419. negro = n-1;
  420.  
  421.     /* para todos los colores */
  422. for(i=0;i<n;++i)
  423.     {
  424.         /* calcular nivel de gris */
  425.     f=(0.30*(double)*paleta++)+
  426.         (0.59*(double)*paleta++)+
  427.         (0.11*(double)*paleta++);
  428.     if(f>255.0) f=255.0;
  429.         /* calcular niveles de blanco y negro */
  430.     paletagris[i]= mapagris[(char)f];
  431.     if(paletagris[i]<negro) negro = paletagris[i];
  432.     if(paletagris[i]>blanco) blanco = paletagris[i];
  433.     }
  434. }
  435.  
  436. /*---- FIN FUNCION -----------------------------------------------------------*/
  437.  
  438.  
  439. /*---- FUNCION: void DITHERpixel(int x,int y,int err) --------------------------
  440.  
  441.     Descripción:
  442.  
  443.         Esta función aplica la difusión de error de un pixel a los pixels
  444.         correspondientes según el método de dithering empleado
  445.  
  446.     Parámetros:
  447.  
  448.         int x: coordenada x del pixel
  449.         int y: coordenada y del pixel
  450.         int err: error de difusión
  451.  
  452. ---- CODIGO: -----------------------------------------------------------------*/
  453.  
  454. void DITHERpixel(int x,int y,int err)
  455. {
  456.     /* difundir errores a los pixels implicados, según el método usado */
  457. switch(metodo)
  458.     {
  459.     case FLOYD:
  460.             PonerPixel(x+1,y,LeerPixel(x+1,y)+((7*err)/16));
  461.             PonerPixel(x-1,y+1,LeerPixel(x-1,y+1)+((3*err)/16));
  462.             PonerPixel(x,y+1,LeerPixel(x,y+1)+((5*err)/16));
  463.             PonerPixel(x+1,y+1,LeerPixel(x+1,y+1)+(err/16));
  464.     break;
  465.     case STUCKI:
  466.             PonerPixel(x+2,y,LeerPixel(x+2,y)+((8*err)/42));
  467.             PonerPixel(x+1,y,LeerPixel(x+1,y)+((4*err)/42));
  468.             PonerPixel(x-2,y+1,LeerPixel(x-2,y+1)+((2*err)/42));
  469.             PonerPixel(x-1,y+1,LeerPixel(x-1,y+1)+((4*err)/42));
  470.             PonerPixel(x,y+1,LeerPixel(x,y+1)+((8*err)/42));
  471.             PonerPixel(x+1,y+1,LeerPixel(x+1,y+1)+((4*err)/42));
  472.             PonerPixel(x+2,y+1,LeerPixel(x+2,y+1)+((2*err)/42));
  473.             PonerPixel(x-2,y+2,LeerPixel(x-2,y+2)+((1*err)/42));
  474.             PonerPixel(x-1,y+2,LeerPixel(x-1,y+2)+((2*err)/42));
  475.             PonerPixel(x,y+2,LeerPixel(x,y+2)+((4*err)/42));
  476.             PonerPixel(x+1,y+2,LeerPixel(x+1,y+2)+((2*err)/42));
  477.             PonerPixel(x+2,y+2,LeerPixel(x+2,y+2)+((1*err)/42));
  478.         break;
  479.     case BURKES:
  480.             PonerPixel(x+2,y  ,LeerPixel(x+2,y  )+((8*err)/32));
  481.             PonerPixel(x+1,y  ,LeerPixel(x+1,y  )+((4*err)/32));
  482.             PonerPixel(x-2,y+1,LeerPixel(x-2,y+1)+((2*err)/32));
  483.             PonerPixel(x-1,y+1,LeerPixel(x-1,y+1)+((4*err)/32));
  484.             PonerPixel(x  ,y+1,LeerPixel(x  ,y+1)+((8*err)/32));
  485.             PonerPixel(x+1,y+1,LeerPixel(x+1,y+1)+((4*err)/32));
  486.             PonerPixel(x+2,y+1,LeerPixel(x+2,y+1)+((2*err)/32));
  487.     break;
  488.     }
  489. }
  490.  
  491. /*---- FIN FUNCION -----------------------------------------------------------*/
  492.  
  493.  
  494. /*---- FUNCION: void LeerPixel(int x,int y) ------------------------------------
  495.  
  496.     Descripción:
  497.  
  498.         Esta función devuelve el valor del pixel x,y desde la línea correspondiente
  499.         del buffer de entrada
  500.  
  501.     Parámetros:
  502.  
  503.         int x: coordenada x del pixel
  504.         int y: coordenada y del pixel
  505.  
  506. ---- CODIGO: -----------------------------------------------------------------*/
  507.  
  508. int LeerPixel(int x,int y)
  509. {
  510.     /* leer pixel desde la entrada */
  511. return(BufferEntrada[y-ultima][x]);
  512. }
  513.  
  514. /*---- FIN FUNCION -----------------------------------------------------------*/
  515.  
  516.  
  517. /*---- FUNCION: void PonerPixel(int x,int y,int n) -----------------------------
  518.  
  519.     Descripción:
  520.  
  521.         Esta función pone nuevo color al pixel x,y en la línea correspondiente
  522.         del buffer de entrada, transmite el error al pixel.
  523.  
  524.     Parámetros:
  525.  
  526.         int x: coordenada x del pixel
  527.         int y: coordenada y del pixel
  528.         int n: nivel de gris
  529.  
  530. ---- CODIGO: -----------------------------------------------------------------*/
  531.  
  532. void PonerPixel(int x,int y,int n)
  533. {
  534.     /* poner nuevo color a un pixel (transmitir error) en el buffer de entrada */
  535. if(x>=0 && x < anchura && y >= 0 && y < altura)
  536.     {
  537.     if(n<negro) n=negro;
  538.     if(n>blanco) n=blanco;
  539.     BufferEntrada[y-ultima][x]=n;
  540.     }
  541. }
  542.  
  543. /*---- FIN FUNCION -----------------------------------------------------------*/
  544.  
  545.  
  546. /*---- FUNCION: void EscribirPixel(int x,int y,int n) -----------------------------
  547.  
  548.     Descripción:
  549.  
  550.         Esta función pone el pixel x,y en el buffer de salida,
  551.         desplazando los bits según la posición del pixel.
  552.  
  553.     Parámetros:
  554.  
  555.         int x: coordenada x del pixel
  556.         int y: coordenada y del pixel
  557.         int n: color (blanco o negro)
  558.  
  559. ---- CODIGO: -----------------------------------------------------------------*/
  560.  
  561. void EscribirPixel(int x,int y,int n)
  562. {
  563.     /* si existe el pixel...*/
  564. if(x>=0 && x < anchura && y >= 0 && y < altura)
  565.     {
  566.         /* poner blanco o negro, desplazando los bits según la posición */
  567.     if(n)
  568.         BufferSalida[x>>3] |= (0x80>>(x & 0x0007));
  569.     else
  570.         BufferSalida[x>>3] &= ~(0x80>>(x & 0x0007));
  571.     }
  572. }
  573.  
  574. /*---- FIN FUNCION -----------------------------------------------------------*/